﻿using AutoMapper;
using HamcoWcs.Contract;
using HamcoWcs.Contract.ContractCommon;
using HamcoWcs.Contract.ContractMes;
using HamcoWcs.DAL;
using HamcoWcs.Entitys.DeviceErrors;
using HamcoWcs.Entitys.MainTasks;
using HamcoWcs.Entitys.MesMsgQueues;
using HamcoWcs.Entitys.WcsLocations;
using HamcoWcs.Models.Common;
using HamcoWcs.Models.Common.Enums;
using HamcoWcs.Models.DeviceMsgs;
using HamcoWcs.Models.Devices;
//using HamcoWcs.Models.MesMessages;
using HamcoWcs.Models.MesMsgQueues;
using HamcoWcs.Models.NodeInfos;
using HamcoWcs.Models.TibcoMessage;
using HamcoWcs.Service.Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Xml;

namespace HamcoWcs.Service.Mes
{
    [AutoInject(typeof(IMesCommunicateService), InjectType.Scope)]
    public class MesCommunicateService : ScopeServiceBase, IMesCommunicateService
    {
        #region Constructor


        private readonly AutomaticStorageInfo _asrs;
        private readonly ILoggerService _loggerService;
        private readonly IBaseConfigService _baseConfigService;
        public MesCommunicateService(AutomaticStorageInfo asrs, WcsDbContext wcsDbContext,
            IMapper mapper,
            ILoggerService loggerService,
            IBaseConfigService baseConfigService)
            : base(wcsDbContext, mapper)
        {
            _asrs = asrs;
            _loggerService = loggerService;
            _baseConfigService = baseConfigService;
        }

        #endregion

        #region ppk

        public void MachineControlStateChanged(NodeInfoDto machine)
        {
            var body = new MachineControlStateChangedMessageBody(machine.NodeName, machine.MachineControlState.ToString());
            var message = new MachineControlStateChangedMessage(body);
            AddMesMessageQueue(message);
        }

        public void MachineStateChanged(NodeInfoDto machine)
        {
            var body = new MachineStateChangedMessageBody(machine.NodeName, machine.MachineState.ToString());
            var message = new MachineStateChangedMessage(body);
            AddMesMessageQueue(message);
        }
        public void MachineStateChanged(string machineName, EnumMachineState state)
        {
            var body = new MachineStateChangedMessageBody(machineName, state.ToString());
            var message = new MachineStateChangedMessage(body);
            AddMesMessageQueue(message);
        }

        public void MachineStateChanged(PconDto pcon)
        {
            var machine = pcon.Machine;
            var body = new MachineStateChangedMessageBody(machine.NodeName, machine.MachineState.ToString());
            var alarm = AutomaticStorageInfo.Alarms.FirstOrDefault(x => x.Code == pcon.ErrorCode.ToString() && x.Module == "pcon");

            var comment = "UNK";
            if (alarm != null)
            {
                comment = $"ErrorCode:{alarm.Code},Desc:{alarm.AlarmName}";
            }

            body.EventComment = comment;
            var message = new MachineStateChangedMessage(body);
            AddMesMessageQueue(message);
        }

        public void MachineStateChanged(SrmDto srm)
        {
            var machine = srm.Aisle;
            var body = new MachineStateChangedMessageBody(machine.NodeName, machine.MachineState.ToString());
            var alarm = AutomaticStorageInfo.Alarms.FirstOrDefault(x => x.Code == srm.ErrorCode.ToString() && x.Module == "srm");

            var comment = "UNK";
            if (alarm != null)
            {
                comment = $"ErrorCode:{alarm.Code},Desc:{alarm.AlarmName}";
            }

            body.EventComment = comment;
            var message = new MachineStateChangedMessage(body);
            AddMesMessageQueue(message);
        }


        public void PortStateChanged(PortStateChangedMessage message)
        {
            AddMesMessageQueue(message);
        }

        public void PortStateChanged(PconDto pcon, PconRecvMsg msg)
        {
            if (pcon.PconMode == msg.PconMode) return;


            string state = "OUTOFSERVICE";
            if (msg.PconMode == 1 || msg.PconMode == 6 || msg.PconMode == 7)
            {
                state = "INSERVICE";
            }

            PortStateChanged(new PortStateChangedMessage(new PortStateChangedMessageBody(pcon.MachineName, pcon.PortName, state)));
        }

        public void PortStateChanged(PconDto pcon)
        {
            string state = "OUTOFSERVICE";
            if (pcon.PconMode == 1 || pcon.PconMode == 6 || pcon.PconMode == 7)
            {
                state = "INSERVICE";
            }

            // MES-不是交互口的不报
            if (pcon.MachineName.Contains("CJRCV")
             || pcon.MachineName.Contains("CJMCV"))
            {
                PortStateChanged(new PortStateChangedMessage(new PortStateChangedMessageBody(pcon.MachineName, pcon.PortName, state)));
            }
        }

        public void MachineModeChangeRequest(MachineModeChangeMessage message)
        {
            AddMesMessageQueue(message);
        }

        public void MachineModeChangeRequest(PconDto pcon, string mode)
        {
            MachineModeChangeRequest(new MachineModeChangeMessage(new MachineModeChangeBody(pcon.MachineName, mode.ToUpper(), pcon.PortName)));
        }

        public void MachineModeChangeReply(MachineModeChangeMessage message)
        {
            AddMesMessageQueue(message);
        }

        public void ChangeMachinePalletTypeRequest(ChangeMachinePalletTypeMessage message)
        {
            AddMesMessageQueue(message);
        }

        public void ChangeMachinePalletTypeRequest(PconDto pcon, string type)
        {
            var body = new ChangeMachinePalletTypeMessageBody()
            {
                EventUser = pcon.MachineName,
                PalletType = type,
                MachineName = pcon.MachineName,
                PortName = pcon.PortName
            };
            var message = new ChangeMachinePalletTypeMessage(body);
            AddMesMessageQueue(message);
        }

        public void PalletAndBoxAssignRequest(PalletAndBoxAssignMessage message)
        {
            AddMesMessageQueue(message);
        }



        public void ValidatePalletInputRequest(ValidatePalletInputMessage message)
        {
            AddMesMessageQueue(message);
        }


        public void ValidatePalletListRequest(ValidatePalletListMessage message)
        {
            AddMesMessageQueue(message);
        }



        public void PalletLocationChangedReport(PalletLocationChangedReportMessage message)
        {
            AddMesMessageQueue(message);
        }

        public void PortTransferStateChanged(PortTransferStateChangedMessage message)
        {
            AddMesMessageQueue(message);
        }

        public void PortTransferStateChanged(PconDto pcon)
        {
            var message = new PortTransferStateChangedMessage(new PortTransferStateChangedMessageBody()
            {
                EventUser = pcon.MachineName,
                LineName = pcon.MachineName,
                PortList = new PortList(new List<Port> { new Port(pcon) })
            });
            AddMesMessageQueue(message);
        }

        public void PalletRequestTransportJobRequest(PalletRequestTransportJobMessage message)
        {
            AddMesMessageQueue(message);
        }

        public void PalletRequestTransportJobReply(PalletRequestTransportJobMessage message)
        {
            AddMesMessageQueue(message);
        }

        public void PalletTransportJobStarted(PalletTransportJobStartedMessage message)
        {
            AddMesMessageQueue(message);
        }

        public void PalletTransportJobStartedByAGV(PalletTransportJobStartedByAGVMessage message)
        {
            AddMesMessageQueue(message);
        }

        public void PalletLocationChanged(PalletLocationChangedMessage message)
        {
            AddMesMessageQueue(message);
        }

        public void PalletTransportJobCompleted(PalletTransportJobCompletedMessage message)
        {
            AddMesMessageQueue(message);
        }

        public void PalletTransportJobCompleted(MainTask mainTask)
        {
            var body = new PalletTransportJobCompletedMessageBody()
            {
                TransportJobName = mainTask.TaskId,
                PalletName = mainTask.UnitId,
                TransferState = mainTask.DesType == "SHELF" ? "INSTK" : "ONEQP",
                CurrentMachineName = mainTask.DesMachine,
                CurrentPositionName = mainTask.DesPosition,
                CurrentPositionType = mainTask.DesType,
                CurrentZoneName = mainTask.DesZone
            };

            var message = new PalletTransportJobCompletedMessage(body);
            AddMesMessageQueue(message);
        }

        public void AreYouThereRequest()
        {
            var message = new AreYouThereMessage(new AreYouThereMessageBody("CJSTW100"));
            //AddMesMessageQueue(message);

            var content = XmlHelper.Serialize(message);
            var mesMsgQueue = new MesMsgQueueDto(content)
            {
                EventName = "AreYouThereRequest",
                TransactionId = XmlHelper.GetTransactionId(content),
                RequestType = EnumMesRequestType.Request,
            };

            var msgEntity = _mapper.Map<MesMsgQueue>(mesMsgQueue);
            _wcsDbContext.MesMsgQueues.Add(msgEntity);
            _wcsDbContext.SaveChanges();
        }

        public void InventoryPalletDataRequest(InventoryPalletDataReportMessage message)
        {
            AddMesMessageQueue(message);
        }
        public void InventoryPalletDataReport(InventoryPalletDataReportMessage message)
        {
            AddMesMessageQueue(message);
        }

        public void InventoryZoneDataRequest(InventoryZoneDataReportMessage message)
        {
            AddMesMessageQueue(message);
        }

        //public void PalletTransportJobTerminatedByAGV(PalletTransportJobTerminatedByAGVMessage message)
        //{
        //    AddMesMessageQueue(message);
        //}

        public void PalletTransportJobTerminatedByAGV(MainTask mainTask, string locState = "")
        {
            var body = new PalletTransportJobTerminatedByAGVMessageBody()
            {
                TransportJobName = mainTask.TaskId,
                PalletName = mainTask.UnitId,
                TransferState = mainTask.DesType == "SHELF" ? "INSTK" : "ONEQP",
                CurrentMachineName = mainTask.CurrentMachine,
                CurrentPositionName = mainTask.CurrentPosition,
                CurrentPositionType = mainTask.CurrentType,
                CurrentZoneName = mainTask.CurrentZone,
                PALLETLOCSTATE = locState
            };
            var message = new PalletTransportJobTerminatedByAGVMessage(body);
            AddMesMessageQueue(message);
        }




        public void PalletTransportPriorityChanged(string jobName, string priority)
        {
            var message = new PalletTransportPriorityChangedMessage(new PalletTransportPriorityChangedMessageBody(jobName, priority));
            AddMesMessageQueue(message);
        }

        public void GetPalletInfoRequest(string palletName)
        {
            var body = new GetPalletInfoRequestMessageBody(palletName);
            var message = new GetPalletInfoRequestMessage(body);
            AddMesMessageQueue(message);
        }
        public void AlarmReport(AlarmReportMessageBody body)
        {
            var message = new AlarmReportMessage(body);
            AddMesMessageQueue(message);
        }

        public void AlarmReportSet(DeviceErrorQueue d)
        {
            var machineName = d.MachineName.ReName();
            if (machineName.IsNullOrEmpty())
            {
                return;
            }
            var body = new AlarmReportMessageBody()
            {
                MACHINENAME = d.MachineName,
                UNITNAME = d.PortName,
                ALARMCODE = d.ErrorCode,
                ALARMLEVEL = d.ErrorLevel,
                ALARMSTATE = "SET",
                ALARMTEXT = d.ErrorDetail,
            };
            AlarmReport(body);
        }
        public void AlarmReportClear(DeviceErrorQueue d)
        {
            var machineName = d.MachineName.ReName();
            if (machineName.IsNullOrEmpty())
            {
                return;
            }
            var body = new AlarmReportMessageBody()
            {
                MACHINENAME = d.MachineName,
                UNITNAME = d.PortName,
                ALARMCODE = d.ErrorCode,
                ALARMLEVEL = d.ErrorLevel,
                ALARMSTATE = "CLEAR",
                ALARMTEXT = d.ErrorDetail,
            };
            AlarmReport(body);
        }

        #endregion

        private void AddMesMessageQueue(object message, [CallerMemberName] string methodName = "")
        {
            //if (!GlobalValue.WCSConnectState) return;
            var content = XmlHelper.Serialize(message);


            var mesMsgQueue = new MesMsgQueueDto(content)
            {
                EventName = methodName,
                TransactionId = XmlHelper.GetTransactionId(content)
            };

            if (methodName.ToUpper().Contains("REQUEST"))
                mesMsgQueue.RequestType = EnumMesRequestType.Request;

            var msgEntity = _mapper.Map<MesMsgQueue>(mesMsgQueue);

            //if ((INIT_STATE == EnumMesInitState.None || INIT_STATE == EnumMesInitState.Connecting) && methodName != "AreYouThereRequest")
            //{
            //    // 未连接成功时先缓存
            //    GlobalValue.MesMsgQueueBuffer.Add(msgEntity);
            //}
            //else
            //{
            //    _wcsDbContext.MesMsgQueues.Add(msgEntity);
            //    _wcsDbContext.SaveChanges();
            //}

            _wcsDbContext.MesMsgQueues.Add(msgEntity);
            _wcsDbContext.SaveChanges();
        }

        //private void AddMesMessageQueue(BaseMesBody body, string listener = "", [CallerMemberName] string methodName = "")
        //{
        //    if (string.IsNullOrEmpty(methodName))
        //        // 0为本身的方法:1为调用方法
        //        methodName = (new StackTrace()).GetFrame(1).GetMethod().Name;
        //    var message = new MesMessage(methodName, listener: listener, body: body);
        //    var content = XmlHelper.Serialize(message);
        //    var mesMsgQueue = new MesMsgQueueDto(content)
        //    {
        //        Subject = methodName
        //    };

        //    if (methodName.ToUpper().Contains("REQUEST"))
        //        mesMsgQueue.RequestType = EnumMesRequestType.Request;

        //    var msgEntity = _mapper.Map<MesMsgQueue>(mesMsgQueue);

        //    if ((INIT_STATE == EnumMesInitState.None || INIT_STATE == EnumMesInitState.Connecting) && methodName != "AreYouThereRequest")
        //    {
        //        // 未连接成功时先缓存
        //        GlobalValue.MesMsgQueueBuffer.Add(msgEntity);
        //    }
        //    else
        //    {
        //        _wcsDbContext.MesMsgQueues.Add(msgEntity);
        //        _wcsDbContext.SaveChanges();
        //    }
        //}

        public void SendBuffer()
        {
            //_wcsDbContext.MesMsgQueues.AddRange(GlobalValue.MesMsgQueueBuffer);
            //GlobalValue.MesMsgQueueBuffer.Clear();

            var subjects = new string[]
            {
                "MachineControlStateChanged",
                "MachineStateChanged",
                "PortStateChanged",
                "PalletTransportJobStarted",
                //"PortTransferStateChanged",
                "InventoryPalletDataReport",
                "InventoryZoneDataReport",
            };

            foreach (var subject in subjects)
            {
                var msgs = GlobalValue.MesMsgQueueBuffer.Where(d => d.EventName == subject).ToList();
                _wcsDbContext.MesMsgQueues.AddRange(msgs);
                _wcsDbContext.SaveChanges();
                Thread.Sleep(200);
            }

            GlobalValue.MesMsgQueueBuffer.Clear();
        }

        public void MachineFrequencyRequest(string machineName, string frequency)
        {
            var body = new MachineFrequencyMessageBody(machineName, frequency);
            var message = new MachineFrequencyMessage(body);
            AddMesMessageQueue(message);
        }

        public void SpacerCarrierChangeRequest(string machineName, string carrierName, string spacerQuantity, string settingCode)
        {
            var body = new SpacerCarrierChangeMessageBody()
            {
                MACHINENAME = machineName,
                EVENTUSER = machineName,
                CARRIERNAME = carrierName,
                SPACERQUANTITY = spacerQuantity,
                SETTINGCODE = settingCode,
            };
            var message = new SpacerCarrierChangeMessage(body);
            AddMesMessageQueue(message);
        }

        public void PalletAlarmReport(PconDto con, string lunitId, string runitId)
        {
            var body = new PalletAlarmReportMessageBody()
            {
                MachineName = con.MachineName,
                PortName = con.PortName,
                EventUser = con.MachineName,

                EQPPALLETNAME = con.UnitId,
                LEFTPALLETNAME = lunitId,
                RIGHTPALLETNAME = runitId,
                ALARMCODE = "30001",
                ALARMTEXT = "Abnormal Read"
            };
            var message = new PalletAlarmReportMessage(body);
            AddMesMessageQueue(message);
        }

        public void CreateTransportJobByWCS(MainTask mainTask)
        {
            var transferState = mainTask.SrcType == "SHELF" ? "INSTK" : "MOVING";
            var body = new CreateTransportJobByWCSMessageBody()
            {
                TRANSPORTJOBNAME = mainTask.TaskId,
                PALLETNAME = mainTask.UnitId,
                SOURCEMACHINENAME = mainTask.SrcMachine,
                SOURCEPOSITIONTYPE = mainTask.SrcType,
                SOURCEPOSITIONNAME = mainTask.SrcPosition,
                SOURCEZONENAME = mainTask.SrcZone,
                CURRENTMACHINENAME = mainTask.SrcMachine,
                CURRENTPOSITIONTYPE = mainTask.SrcType,
                CURRENTPOSITIONNAME = mainTask.SrcPosition,
                CURRENTZONENAME = mainTask.SrcZone,
                DESTINATIONMACHINENAME = mainTask.DesMachine,
                DESTINATIONPOSITIONTYPE = mainTask.DesType,
                DESTINATIONPOSITIONNAME = mainTask.DesPosition,
                DESTINATIONZONENAME = mainTask.DesZone,
                PRIORITY = mainTask.Priority,
                TRANSFERSTATE = transferState,
            };
            var message = new CreateTransportJobByWCSMessage(body);
            AddMesMessageQueue(message);
        }

        //新加任务同步
        public void TransportJobListReportByWCS(List<MainTask> mainTasks)
        {

            var body = new TransportJobListReportByWCSMessageBody();

            var t = mainTasks.Select(x => new TRANSPORTJOB()
            {
                PALLETNAME = x.UnitId,
                TRANSFERSTATE = x.SrcType == "SHELF" ? "INSTK" : "MOVING",
                TRANSPORTJOBNAME = x.TaskId,
                CURRENTMACHINENAME = x.SrcMachine,
                CURRENTPOSITIONTYPE = x.SrcType,
                CURRENTPOSITIONNAME = x.SrcPosition,
                CURRENTZONENAME = x.SrcZone,
                PRIORITY = x.Priority,
            }).ToList();

            //var list = new TransportJobList()
            //{
            //    TransportJobs = t
            //};
            body.TRANSPORTJOBLIST = t;

            var message = new TransportJobListReportByWCSMessage(body);
            AddMesMessageQueue(message);
        }
        public void PalletLocStateChanged(WcsLocation loc)
        {
            //if (!string.IsNullOrEmpty(loc.UnitId))
            //{
            //    return;
            //}
            var machineName = loc.ZoneName.Substring(0, 8);

            var body = new PalletLocStateChangedMessageBody()
            {
                MACHINENAME = machineName,
                PALLETLIST = new PalletList(new List<Pallet>
                {
                    new Pallet()
                    {
                        PalletName = loc.UnitId,
                        CurrentPositionName = loc.WcsLocName,
                        CurrentPositionType = "SHELF",
                        CurrentZoneName = loc.ZoneName,
                        PalletLocState = (loc.IsLock || loc.SrmOccupyFlag) ? "BLOCKED" : "UNBLOCKED"
                    }
                })
            };
            var message = new PalletLocStateChangedMessage(body);
            AddMesMessageQueue(message);
        }


        public void CurrentStockerEmptyBoxPlanRequest(string machineName)
        {
            var body = new CurrentStockerEmptyBoxPlanMessageBody()
            {
                MACHINENAME = machineName
            };
            var message = new CurrentStockerEmptyBoxPlanMessage(body);
            AddMesMessageQueue(message);
        }
    }
}
